package com.augmentum.oes.util;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import com.augmentum.oes.annotation.Orm.Column;
import com.augmentum.oes.annotation.Orm.Table;
import com.augmentum.oes.exception.BaseException;
import com.augmentum.oes.exception.DBException;

public final class JDBCUtil {
    private static Connection conn = null;
    static {
        try {
            Class.forName(PropertyUtil.getJDBCInfo("jdbc.driver"));
        } catch (ClassNotFoundException e) {
            throw new DBException(MessageUtils.DB_LOAD_DRIVER_ERROR,
                    MessageUtils.buildMessage(MessageUtils.DB_LOAD_DRIVER_ERROR));
        }
    }

    // Get the connection
    public static Connection getConnection() {
        try {
            String uri = PropertyUtil.getJDBCInfo("jdbc.url");
            conn = DriverManager.getConnection(uri, PropertyUtil.getJDBCInfo("jdbc.username"),
                    PropertyUtil.getJDBCInfo("jdbc.password"));
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DBException(MessageUtils.DB_GET_CONNECT_ERROR,
                    MessageUtils.buildMessage(MessageUtils.DB_GET_CONNECT_ERROR));
        }
        return conn;
    }

    // Close the connection
    public static void close(ResultSet rs, PreparedStatement ps, Connection con) {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            throw new DBException(MessageUtils.DB_CLOSE_ERROR, MessageUtils.buildMessage(MessageUtils.DB_CLOSE_ERROR));
        }
        try {
            if (ps != null) {
                ps.close();
            }
        } catch (SQLException e) {
            throw new DBException(MessageUtils.DB_CLOSE_ERROR, MessageUtils.buildMessage(MessageUtils.DB_CLOSE_ERROR));
        }
        try {
            if (con != null) {
                con.close();
            }
        } catch (SQLException e) {
            throw new DBException(MessageUtils.DB_CLOSE_ERROR, MessageUtils.buildMessage(MessageUtils.DB_CLOSE_ERROR));
        }
    }

    public static <T> Map<String, Object> toMap(T t) {
        Map<String, Object> orm = new HashMap<>();
        Field[] fields = t.getClass().getDeclaredFields();
        for (Field field : fields) {
            Column column = field.getAnnotation(Column.class);
            try {
                field.setAccessible(true);
                Object value = field.get(t);
                if (column != null && value != null) {
                    if (!"".equals(column.value())) {
                        orm.put(column.value(), value);
                    } else {
                        orm.put(field.getName(), value);
                    }
                }
            } catch (IllegalArgumentException | IllegalAccessException e) {
                throw new BaseException(MessageUtils.REFLECT_FAIL);
            }
        }
        return orm;
    }

    public static <T> void toBean(T t, ResultSet rs) {
        Field[] fields = t.getClass().getDeclaredFields();
        try {
            for (Field field : fields) {
                field.setAccessible(true);
                if (field.getAnnotation(Column.class) != null) {
                    Object value = rs.getObject(StringUtil.getAnnoName(field));
                    field.set(t, value);
                }
            }
        } catch (IllegalArgumentException | IllegalAccessException e) {
            throw new BaseException(MessageUtils.REFLECT_FAIL);
        } catch (SQLException e) {
            throw new DBException(MessageUtils.DB_CLOSE_ERROR, MessageUtils.buildMessage(MessageUtils.DB_CLOSE_ERROR));

        }
    }

    public static <T> String getTable(T t) {
        return t.getClass().getAnnotation(Table.class).value();
    }
}
